package top.yqingyu.trans$client.cs.command.impl;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import top.yqingyu.common.function.Progress;
import top.yqingyu.common.qydata.DataMap;
import top.yqingyu.common.utils.FileUtil;
import top.yqingyu.common.utils.IoUtil;
import top.yqingyu.common.utils.StringUtil;
import top.yqingyu.common.utils.ThreadUtil;
import top.yqingyu.qymsg.MsgHelper;
import top.yqingyu.qymsg.QyMsg;
import top.yqingyu.qymsg.bean.TransObj;
import top.yqingyu.trans$client.api.Connection;
import top.yqingyu.trans$client.common.TransChannel;
import top.yqingyu.trans$client.cs.command.Command;
import top.yqingyu.trans$client.main.TransClient;

import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.StandardCharsets;
import java.nio.file.StandardOpenOption;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ThreadPoolExecutor;

public class DownLoad extends Command {
    private static final Logger log = LoggerFactory.getLogger(DownLoad.class);
    private static final ThreadPoolExecutor executor = ThreadUtil.createQyFixedThreadPool(10, 10, 1800, "DOWNLOAD", "t");
    private static final String commandRegx = "^(([d]|[D])ownload).*$";
    private static final String fileSeparator = System.getProperty("file.separator");

    @Override
    public void dealCommand(TransClient client, Connection connection, QyMsg msg) throws Exception {
        super.dealWrite(client, connection, msg);
    }

    @Override
    public void deal(QyMsg msg, TransClient client) throws Exception {
        String msgStr = MsgHelper.gainMsg(msg);
        TransObj transObj = new TransObj();
        msg.putMsg("download");
        String[] split = msgStr.split(" ");
        transObj.setFileName(split[1]);
        msg.putMsgData("download", transObj);
        if (split.length > 2) {
            File file = new File(split[2]);
            if (file.exists() && !file.isDirectory()) {
                throw new IllegalArgumentException(StringUtil.fillBrace("文件已存在{}", split[2]));
            }
        }
        File defPath = new File(client.clientConf.DEFAULT_DOWNLOAD_PATH);
        if (!defPath.exists()) {
            defPath.mkdirs();
        }
        DataMap dataMap = msg.getDataMap();
        Progress progress = (Progress) dataMap.remove("downloadProgress");
        executor.execute(getThread(client, split, progress));
    }

    Thread getThread(TransClient client, String[] splitPath, Progress progress) {
        return new Thread(() -> {
            try {
                Thread.sleep(1500);
            } catch (InterruptedException ignored) {
            }
            SocketChannel transChannel = null;
            try {
                transChannel = TransChannel.getTransChannel(client, client.clientConf.HOST, client.clientConf.PORT3, "download");
                byte[] bytes = client.clientConf.msgTransfer.readQyBytes(transChannel);
                ConcurrentHashMap<String, TransObj> dataMap = IoUtil.deserializationObj(bytes, ConcurrentHashMap.class);
                Set<String> strings = dataMap.keySet();
                for (String string : strings) {
                    String fileId = new String(client.clientConf.msgTransfer.readQyBytes(transChannel), StandardCharsets.UTF_8);
                    TransObj obj = dataMap.get(fileId);
                    long size = obj.getSize();
                    String fileName = obj.getFileName();
                    File file = new File(client.clientConf.DEFAULT_DOWNLOAD_PATH + fileSeparator + fileName);
                    if (splitPath.length > 2) {
                        File tempFile = new File(splitPath[2]);
                        if (tempFile.isDirectory()) {
                            file = new File(splitPath[2] + fileSeparator + fileName);
                        } else {
                            file = tempFile;
                        }
                    }
                    FileUtil.createSizeFile2(file, size);
                    FileChannel fileChannel = FileChannel.open(file.toPath(), StandardOpenOption.WRITE);
                    long position = 0;
                    long residue = size;
                    ByteBuffer byteBuffer = ByteBuffer.allocateDirect(8 * 1024);
                    do {
                        byteBuffer.clear();
                        fileChannel.position(position);
                        int read = transChannel.read(byteBuffer);
                        byteBuffer.flip();
                        int limit = byteBuffer.limit();
                        do {
                            position += fileChannel.write(byteBuffer, position);
                        } while (limit != byteBuffer.position());
                        if (progress != null) {
                            progress.callback(fileName, size, position);
                        }
                        residue -= read;
                    } while (residue != 0);
                    fileChannel.close();
                }
                transChannel.close();
            } catch (Exception e) {
                if (transChannel != null) {
                    try {
                        transChannel.close();
                    } catch (IOException ex) {
                        log.error("", ex);
                    }
                }
                log.error("", e);
            }
        });
    }
}
